package com.xcity.game.combat;

import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.annotation.JSONField;
import com.xcity.game.combat.attr.CombatAttribute;
import com.xcity.game.combat.attr.CombatAttributeType;
import com.xcity.game.combat.buff.CombatBuff;
import com.xcity.game.combat.listener.LifeCycleListener;
import com.xcity.game.combat.skill.CombatSkill;
import com.xcity.game.combat.unit.CombatUnit;
import com.xcity.game.combat.unit.Combatable;
import com.xcity.game.combat.unit.UnitAttribute;
import com.xcity.game.equip.suit4.BaseSuit4;

public abstract class AbstractCombatUnit<C extends Combatable> implements CombatUnit {

	protected C combatable;
	protected CombatTeam team;
	protected Map<CombatAttributeType, CombatAttribute> attrs = Collections.emptyMap();
	protected List<CombatSkill> skills = Collections.emptyList();
	protected List<CombatBuff> buffs;
	protected LifeCycleListener lifeCycleListener;
	protected int index; // 阵型中的位置
	
	protected BaseSuit4 suit4Calc; // 装备4件套效果（员工）
	
	protected AbstractCombatUnit() {}
	
	public AbstractCombatUnit(CombatTeam team, C combatable) {
		this.combatable = combatable;
		this.team = team;
		this.attrs = new EnumMap<CombatAttributeType, CombatAttribute>(CombatAttributeType.class);
	}
	
	@Override
	public int addHp(int value) {
		int hp = (int) getAttributeValue(CombatAttributeType.HP);
		if (value > 0 && hp + value > 0) {
			hp += value;
			int maxHp = getMaxHp();
			if (hp > maxHp)
				hp = maxHp;
			setAttributeValue(CombatAttributeType.HP, hp);
		}
		return hp;
	}

	@Override
	public int decHp(int value) {
		int hp = (int) getAttributeValue(CombatAttributeType.HP);
		if (value > 0) {
			hp -= value;
			if (hp < 0)
				hp = 0;
			setAttributeValue(CombatAttributeType.HP, hp);
		}
		return hp;
	}

	@Override
	public int addMp(int value) {
		int mp = (int) getAttributeValue(CombatAttributeType.MP);
		if (value > 0 && (mp + value) > 0) {
			mp += value;
			int maxMp = getMaxMp();
			if (mp > maxMp)
				mp = maxMp;
			setAttributeValue(CombatAttributeType.MP, mp);
		}
		return mp;
	}

	@Override
	public int decMp(int value) {
		int mp = (int) getAttributeValue(CombatAttributeType.MP);
		if (value > 0) {
			mp -= value;
			if (mp < 0)
				mp = 0;
			setAttributeValue(CombatAttributeType.MP, mp);
		}
		return mp;
	}
	
	@Override
	@JSONField(serialize = false)
	public boolean isDied() {
//		return hp <= 0;
		return getHp() <= 0;
	}

	@Override
	@JSONField(serialize = false)
	public CombatTeam getTeam() {
		return team;
	}
	
	@Override
	public int getIndex() {
		return index;
	}

	@JSONField(name = "skills")
	@Override
	public List<CombatSkill> getCombatSkills() {
		return skills;
	}
	
	@Override
	public float getAttributeValue(CombatAttributeType type) {
		CombatAttribute attr = attrs.get(type);
		return attr != null ? attr.getValue() : 0f;
	}

	@Override
	public float setAttributeValue(CombatAttributeType type, float value) {
		if (type == CombatAttributeType.HP) {
			int maxHp;
			if (value < 0) {
				value = 0;
			} else if ((maxHp = getMaxHp()) > 0 && value > maxHp) {
				value = maxHp;
			}
		} else if (type == CombatAttributeType.MP) {
			int maxMp;
			if (value < 0) {
				value = 0;
			} else if ((maxMp = getMaxMp()) > 0 && value > maxMp) {
				value = maxMp;
			}
		}
		CombatAttribute attr = attrs.get(type);
		if (attr == null) {
			attr = new UnitAttribute(type, value);
			attrs.put(type, attr);
		} else {
			float oldVal = attr.getValue();
			attr.setValue(value);
			if (lifeCycleListener != null && type == CombatAttributeType.HP) {
				if (oldVal > 0 && value <= 0) {
					lifeCycleListener.died(this);
				} else if (oldVal <= 0 && value > 0) {
					lifeCycleListener.relive(this);
				}
			}
		}
		return value;
	}

	@Override
	public CombatSkill findSkillByType(byte type) {
		for (int i = skills.size() - 1; i >= 0; i--) {
			CombatSkill skill = skills.get(i);
			if (skill.getTemplate().getType() == type) {
				return skill;
			}
		}
		return null;
	}

	@Override
	public boolean addBuff(CombatBuff buff) {
		if (buffs == null) {
			buffs = new ArrayList<CombatBuff>(2);
		}
		for (int i = buffs.size() - 1; i >= 0; i--) {
			CombatBuff b = buffs.get(i);
			if (b.getId() == buff.getId()) {
//				return false;
				buffs.remove(i);
				break;
			}
		}
		buffs.add(buff);
		return true;
	}
	
	@Override
	public void removeBuff(CombatBuff buff) {
		if (buffs != null) {
			buffs.remove(buff);
		}
	}
	
	@Override
	public CombatBuff getBuff(int id) {
		for (int i = 0, size = buffs != null ? buffs.size() : 0; i < size; i++) {
			CombatBuff buff = buffs.get(i);
			if (buff.getId() == id) {
				return buff;
			}
		}
		return null;
	}
	
	@JSONField(serialize = false)
	@Override
	public List<CombatBuff> getBuffs() {
		return buffs;
	}

	@Override
	public void roundStart(Round round) {
		if (buffs != null) {
			for (int i = 0, size = buffs.size(); i < size; i++) {
				buffs.get(i).roundStart(round);
			}
		}
	}
	
	@Override
	public CombatUnit preTarget(Action action) {
		for (int i = 0, size = buffs != null ? buffs.size() : 0; i < size; i++) {
			CombatUnit u = buffs.get(i).preTarget(action);
			if (u != null) {
				return u;
			}
		}
		return null;
	}

	@Override
	public void preDamage(ActionEffect effect) {
		if (suit4Calc != null) {
			suit4Calc.preDamage(effect);
		}
		if (buffs != null) {
			for (int i = 0, size = buffs.size(); i < size; i++) {
				buffs.get(i).preDamage(effect);
			}
		}
	}

	@Override
	public void afterDamage(ActionEffect effect) {
		if (suit4Calc != null) {
			suit4Calc.afterDamage(effect);
		}
		if (buffs != null) {
			for (int i = 0, size = buffs.size(); i < size; i++) {
				buffs.get(i).afterDamage(effect);
			}
		}
	}
	
	@Override
	public void preDamage0(ActionEffect effect) {
		if (suit4Calc != null) {
			suit4Calc.preDamage0(effect);
		}
		if (buffs != null) {
			for (int i = 0, size = buffs.size(); i < size; i++) {
				buffs.get(i).preDamage0(effect);
			}
		}
	}

	@Override
	public void afterDamage0(ActionEffect effect) {
		if (suit4Calc != null) {
			suit4Calc.afterDamage0(effect);
		}
		if (buffs != null) {
			for (int i = 0, size = buffs.size(); i < size; i++) {
				buffs.get(i).afterDamage0(effect);
			}
		}
	}

	@Override
	public void roundEnd(Round round) {
		if (suit4Calc != null) {
			suit4Calc.roundEnd(round);
		}
		if (buffs != null) {
			for (int i = buffs.size() - 1; i >= 0; i--) {
				CombatBuff buff = buffs.get(i);
				buff.roundEnd(round);
				if (buff.getState() == CombatBuff.STATE_REMOVED) {
					buffs.remove(i);
				}
			}
		}
	}

	@Override
	public void preAction(Action action) {
		for (int i = 0, size = buffs != null ? buffs.size() : 0; i < size; i++) {
			buffs.get(i).preAction(action);
		}
	}

	@Override
	public void afterAction(Action action) {
		if (suit4Calc != null) {
			suit4Calc.afterAction(action);
		}
		for (int i = 0, size = buffs != null ? buffs.size() : 0; i < size; i++) {
			buffs.get(i).afterAction(action);
		}
	}
	
	@Override
	public void setLifeCycleListener(LifeCycleListener listener) {
		this.lifeCycleListener = listener;
	}
	
//	@JSONField(serialize = false)
//	@Override
//	public float getSTR() {
//		return combatable.getSTR();
//	}
//
//	@JSONField(serialize = false)
//	@Override
//	public float getINT() {
//		return combatable.getINT();
//	}
//
//	@JSONField(serialize = false)
//	@Override
//	public float getAGI() {
//		return combatable.getAGI();
//	}
//
//	@JSONField(serialize = false)
//	@Override
//	public float getSPI() {
//		return combatable.getSPI();
//	}
//
//	@JSONField(serialize = false)
//	@Override
//	public float getSTA() {
//		return combatable.getSTA();
//	}
	
//	@JSONField(serialize = true)
	@Override
	public int getHp() {
		return (int) getAttributeValue(CombatAttributeType.HP);
	}

//	@JSONField(serialize = true)
	@Override
	public int getMaxHp() {
		return (int) getAttributeValue(CombatAttributeType.MAX_HP);
	}

//	@JSONField(serialize = true)
	@Override
	public int getMp() {
		return (int) getAttributeValue(CombatAttributeType.MP);
	}

//	@JSONField(serialize = true)
	@Override
	public int getMaxMp() {
		return (int) getAttributeValue(CombatAttributeType.MAX_MP);
	}
	
	@Override
	public long getId() {
		return combatable.getId();
	}

	@Override
	public byte getSex() {
		return combatable.getSex();
	}

	@Override
	public String getName() {
		return combatable.getName();
	}

	@Override
	public String getIcon() {
		return combatable.getIcon();
	}

	@Override
	public int getLevel() {
		return combatable.getLevel();
	}

	@Override
	public int compareTo(CombatUnit o) {
		return o.getAttackSpeed() - getAttackSpeed();
	}
	
	public int getQualityLvl() {
		return 0;
	}

}
